/**
 * Copyright (c) Huawei Technologies Co., Ltd. 2022. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "gatherv2_tiling.h"
#include <vector>
#include<inttypes.h>
#include <nlohmann/json.hpp>
#include "op_tiling.h"

namespace TbeReduce {

    void InitGatherCompileParams(GatherCompileParams &params)
    {
        params.ub_size = 0;
        params.l1_size = 0;
        params.core_num = 0;
        params.params_d_size = 0;
        params.indices_d_size = 0;
        params.batch_dims = 0;
        params.impl_mode = IMPL_MODE_DEFAULT_VALUE;
        params.is_preprocessed = false;
    }

    void InitGatherShapeInfo(const std::string &op_type, GatherShapeInfo &params, const TeOpParas &opParas)
    {
        bool verify_input = !opParas.inputs[0].tensor.empty() && !opParas.inputs[1].tensor.empty() &&
                            !opParas.outputs[0].tensor.empty();
        if (!verify_input) {
            HCCL_ERROR("opType[%s] input shape cannot be empty", op_type.c_str());
            return;
        }

        params.params_shape = opParas.inputs[0].tensor[0].shape;
        params.indices_shape = opParas.inputs[1].tensor[0].shape;
        params.indices_ori_shape = opParas.inputs[1].tensor[0].oriShape;
        params.y_shape = opParas.outputs[0].tensor[0].shape;
    }

    void InitGatherV2Params(GatherV2TilingParams &params)
    {
        params.tiling_mode = 0;
        params.params_pre = 1;
        params.params_axis = 1;
        params.params_row = 1;
        params.indices_num = 1;
        params.cache_params = 0;
        params.need_core_num = 0;
        params.tail_process_core = 0;
        params.indices_num_each_core = 0;
        params.indices_num_remaining = 0;
        params.indices_loop_num = 0;
        params.indices_row_num_once = 0;
        params.indices_row_num_last = 0;
        params.row_num_once_ub = 0;
        params.row_num_once_tail_ub = 0;
        params.inner_loop_num = 0;
        params.row_num_last_ub = 0;
        params.row_num_last_tail_ub = 0;
        params.inner_loop_num_last = 0;
        params.params_total = 0;
        params.one_row_loop = 0;
        params.one_row_tail = 0;
        params.params_pre_each_core = 0;
        params.params_pre_remaining = 0;
        params.indices_row = 1;
        params.params_batch_each_core = 1;
        params.params_batch_remaining = 0;
        params.params_batch = 1;
        params.indicesBatch = 1;
        params.half_remain_ub_size = 1;
        params.half_ub_size = 1;
    }

    void SetGatherV2Params(GatherV2TilingParams &Params, OpRunInfo &run_info)
    {
        // set tiling data
        ByteBufferPut(run_info.tilingData, Params.tiling_mode);
        ByteBufferPut(run_info.tilingData, Params.params_pre);
        ByteBufferPut(run_info.tilingData, Params.params_axis);
        ByteBufferPut(run_info.tilingData, Params.params_row);
        ByteBufferPut(run_info.tilingData, Params.indices_num);
        ByteBufferPut(run_info.tilingData, Params.cache_params);
        ByteBufferPut(run_info.tilingData, Params.need_core_num);
        ByteBufferPut(run_info.tilingData, Params.tail_process_core);
        ByteBufferPut(run_info.tilingData, Params.indices_num_each_core);
        ByteBufferPut(run_info.tilingData, Params.indices_num_remaining);
        ByteBufferPut(run_info.tilingData, Params.indices_loop_num);
        ByteBufferPut(run_info.tilingData, Params.indices_row_num_once);
        ByteBufferPut(run_info.tilingData, Params.indices_row_num_last);
        ByteBufferPut(run_info.tilingData, Params.row_num_once_ub);
        ByteBufferPut(run_info.tilingData, Params.row_num_once_tail_ub);
        ByteBufferPut(run_info.tilingData, Params.inner_loop_num);
        ByteBufferPut(run_info.tilingData, Params.row_num_last_ub);
        ByteBufferPut(run_info.tilingData, Params.row_num_last_tail_ub);
        ByteBufferPut(run_info.tilingData, Params.inner_loop_num_last);
        ByteBufferPut(run_info.tilingData, Params.params_total);
        ByteBufferPut(run_info.tilingData, Params.one_row_loop);
        ByteBufferPut(run_info.tilingData, Params.one_row_tail);
        ByteBufferPut(run_info.tilingData, Params.params_pre_each_core);
        ByteBufferPut(run_info.tilingData, Params.params_pre_remaining);
        ByteBufferPut(run_info.tilingData, Params.indices_row);
        ByteBufferPut(run_info.tilingData, Params.params_batch_each_core);
        ByteBufferPut(run_info.tilingData, Params.params_batch_remaining);
        ByteBufferPut(run_info.tilingData, Params.params_batch);
    }

    void PrintGatherV2Params(const GatherV2TilingParams &params, const std::string &op_type)
    {
        HCCL_DEBUG(" tiling_mode=%ld.", params.tiling_mode);
        HCCL_DEBUG(" params_pre=%ld.", params.params_pre);
        HCCL_DEBUG(" params_axis=%ld.", params.params_axis);
        HCCL_DEBUG(" params_row=%ld.", params.params_row);
        HCCL_DEBUG(" indices_num=%ld.", params.indices_num);
        HCCL_DEBUG("cache_params=%ld.", params.cache_params);
        HCCL_DEBUG("need_core_num=%ld.", params.need_core_num);
        HCCL_DEBUG("tail_process_core=%ld.", params.tail_process_core);
        HCCL_DEBUG("indices_num_each_core=%ld.", params.indices_num_each_core);
        HCCL_DEBUG("indices_num_remaining=%ld.", params.indices_num_remaining);
        HCCL_DEBUG("indices_loop_num=%ld.", params.indices_loop_num);
        HCCL_DEBUG("indices_row_num_once=%ld.", params.indices_row_num_once);
        HCCL_DEBUG("indices_row_num_last=%ld.", params.indices_row_num_last);
        HCCL_DEBUG("row_num_once_ub=%ld.", params.row_num_once_ub);
        HCCL_DEBUG("row_num_once_tail_ub=%ld.", params.row_num_once_tail_ub);
        HCCL_DEBUG("inner_loop_num=%ld.", params.inner_loop_num);
        HCCL_DEBUG("row_num_last_ub=%d.", params.row_num_last_ub);
        HCCL_DEBUG("row_num_last_tail_ub=%ld.", params.row_num_last_tail_ub);
        HCCL_DEBUG("inner_loop_num_last=%ld.", params.inner_loop_num_last);
        HCCL_DEBUG("params_total=%ld.", params.params_total);
        HCCL_DEBUG("one_row_loop=%ld.", params.one_row_loop);
        HCCL_DEBUG("one_row_tail=%ld.", params.one_row_tail);
        HCCL_DEBUG("params_pre_each_core=%ld.", params.params_pre_each_core);
        HCCL_DEBUG("params_pre_remaining=%ld.", params.params_pre_remaining);
        HCCL_DEBUG("indices_row=%ld.", params.indices_row);
        HCCL_DEBUG("params_batch_each_core=%ld.", params.params_batch_each_core);
        HCCL_DEBUG("params_batch_remaining=%ld.", params.params_batch_remaining);
        HCCL_DEBUG("params_batch=%ld.", params.params_batch);
    }

    bool CheckAxisAndBatchdims(const std::string &op_type, const GatherShapeInfo &shape_info, int64_t &axis,
        GatherCompileParams &compile_params)
    {
        int64_t paramsDims = shape_info.params_shape.size();
        int64_t indices_dims = shape_info.indices_shape.size();
        if (paramsDims <= 0 || indices_dims <= 0) {
            HCCL_ERROR("op[%s] paramsDims or indices_dims is 0", op_type.c_str());
            return false;
        }
        if (axis < -paramsDims || axis >= paramsDims) {
            HCCL_ERROR("op[%s] axis is invalid.", op_type.c_str());
            return false;
        }
        if (axis < 0) {
            axis += paramsDims;
        }

        if (compile_params.batch_dims != 0) {
            if (compile_params.batch_dims < -indices_dims || compile_params.batch_dims >= indices_dims) {
                HCCL_ERROR("op[%s] batch_dims is invalid.", op_type.c_str());
                return false;
            }
            if (compile_params.batch_dims < 0) {
                compile_params.batch_dims += indices_dims;
            }
            if (compile_params.batch_dims >= paramsDims) {
                HCCL_ERROR("op[%s] batch_dims must be less than rank(params).", op_type.c_str());
                return false;
            }
            if (compile_params.batch_dims > axis) {
                HCCL_ERROR("op[%s] batch_dims must be less than or equal to axis.", op_type.c_str());
                return false;
            }
            for (int i = 0; i < compile_params.batch_dims; i++) {
                if (shape_info.params_shape[i] != shape_info.indices_shape[i]) {
                    HCCL_ERROR("op[%s] Params.shape[:batch_dims] should be equal to indices.shape[:batch_dims]",
                               op_type.c_str());
                    return false;
                }
            }
        }

        return true;
    }

    void GetV2GatherCompileParams(const std::string &op_type, const GatherCompileInfos &compile_info_vec,
        const TeOpParas &op_paras, GatherCompileParams &params)
    {
        params.batch_dims = BATCH_DIMS_DEFAULT_VALUE;

        // string to int64
        EXECEPTION_CATCH((params.batch_dims = std::stoll(op_paras.attrs[0])), return);

        params.core_num = compile_info_vec.core_num;
        params.ub_size = compile_info_vec.ub_size;
        params.l1_size = compile_info_vec.l1_size;
        params.params_d_size = compile_info_vec.params_d_size;
        params.indices_d_size = compile_info_vec.indices_d_size;
        params.impl_mode = compile_info_vec.impl_mode;
        params.is_preprocessed = compile_info_vec.is_preprocessed;
    }

    bool DoImplModeTiling(const std::string &op_type, GatherV2TilingParams &run_params,
        const GatherCompileParams &compile_params)
    {
        if (compile_params.impl_mode != IMPL_MODE_HIGH_PERFORMANCE_VALUE) {
            HCCL_DEBUG("op[%s] [DoImplModeTiling] no need cache params row 0 for impl_mode is not high_performance",
                       op_type.c_str());
            return false;
        }

        if (run_params.params_total * compile_params.params_d_size <= PARAMS_CACHED_UB) {
            HCCL_DEBUG("op[%s] [DoImplModeTiling] no need cache params row 0 for all params can be cached in UB",
                       op_type.c_str());
            return false;
        }

        if (run_params.indices_num < compile_params.core_num * GATHER_BLOCK_SIZE / compile_params.params_d_size) {
            HCCL_DEBUG("op[%s] [DoImplModeTiling] no need cache params row 0 for the num of indices is small",
                       op_type.c_str());
            return false;
        }

        run_params.need_core_num = compile_params.core_num;
        run_params.indices_num_each_core =
                (run_params.indices_num + run_params.need_core_num - 1) / run_params.need_core_num;
        run_params.indices_num_remaining = run_params.indices_num / run_params.need_core_num;

        run_params.tail_process_core = run_params.indices_num % run_params.need_core_num;
        if (run_params.tail_process_core == 0) {
            run_params.tail_process_core = run_params.need_core_num;
        }
        HCCL_DEBUG("[DoImplModeTiling] For the core which blockId < %ld, %ld indices will be process", op_type.c_str(),
                   run_params.tail_process_core, run_params.indices_num_each_core);
        HCCL_DEBUG("[DoImplModeTiling] For the core which blockId >= %ld, %ld indices will be process", op_type.c_str(),
                   run_params.tail_process_core, run_params.indices_num_remaining);

        return true;
    }

    bool DoCacheModeAlignCheck(const std::string &op_type, int64_t axis, GatherV2TilingParams &run_params,
        const GatherCompileParams &compile_params)
    {
        CHECK_WARNING(!(compile_params.impl_mode != IMPL_MODE_HIGH_PERFORMANCE_VALUE),
            "%d,[DoCacheModeAlignCheck] no need simpiling cache, becase current is not high_performance", 1);
        CHECK_WARNING(!(run_params.indices_num <= INDICES_MIN_NUM_FOR_CACHE),
            "[DoCacheModeAlignCheck] no need simpiling cache, but indices_num is %ld",
            run_params.indices_num);
        // if input param size less than cache n number buffer, no need cache mode
        int64_t cache_n_num_max_size = (compile_params.ub_size - RESERVED_UB_SIZE) / CACHE_MODE_UB_SLICE;
        cache_n_num_max_size = cache_n_num_max_size / GATHER_BLOCK_SIZE * GATHER_BLOCK_SIZE;
        CHECK_WARNING(!(run_params.params_total * compile_params.params_d_size < cache_n_num_max_size),
            "[DoCacheModeAlignCheck] no need simpiling cache, but cache_n_num_max_size is %ld", cache_n_num_max_size);
        CHECK_WARNING(!(axis != 0), "[DoCacheModeAlignCheck] no need simpiling cache, but axis is %ld", axis);
        int64_t one_param_row_size = run_params.params_row * compile_params.params_d_size;

        CHECK_WARNING(!(((one_param_row_size > TILING_MODE_15_MAX_PARAM_NUM_SIZE) ||
            (one_param_row_size < GATHER_BLOCK_SIZE) || (one_param_row_size % GATHER_BLOCK_SIZE != 0) ||
                (one_param_row_size * GATHER_BLOCK_SIZE > cache_n_num_max_size))),
            "[DoCacheModeAlignCheck] no need cache mode, but params_row_size is %ld, cache_n_num_max_size is %ld",
            one_param_row_size, cache_n_num_max_size);
        CHECK_WARNING(!(compile_params.core_num == 0),
            "[DoCacheModeAlignCheck] no need simpiling cache, but need_core_num is %ld", compile_params.core_num);
        return true;
    }

    bool DoCacheModeTiling(const std::string &op_type, int64_t axis, GatherV2TilingParams &run_params,
        const GatherCompileParams &compile_params)
    {
        if (!DoCacheModeAlignCheck(op_type, axis, run_params, compile_params)) {
            return false;
        }
        run_params.need_core_num = compile_params.core_num;
        run_params.indices_num_each_core =
                (run_params.indices_num + run_params.need_core_num - 1) / run_params.need_core_num;
        run_params.indices_num_remaining = run_params.indices_num / run_params.need_core_num;

        run_params.tail_process_core = run_params.indices_num % run_params.need_core_num;
        if (run_params.tail_process_core == 0) {
            run_params.tail_process_core = run_params.need_core_num;
        }
        HCCL_DEBUG("[DoCacheModeTiling] For the core which blockId < %ld, %ld indices will be process",
                   op_type.c_str(), run_params.tail_process_core, run_params.indices_num_each_core);
        HCCL_DEBUG("[DoCacheModeTiling] For the core which blockId >= %ld, %ld indices will be process",
                   op_type.c_str(), run_params.tail_process_core, run_params.indices_num_remaining);

        return true;
    }

    bool DoCacheModeNotAlignCheck(const std::string &op_type, int64_t axis, int64_t one_param_row_size,
        GatherV2TilingParams &params, const GatherCompileParams &compile_params)
    {
        CHECK_WARNING(!(compile_params.impl_mode != IMPL_MODE_HIGH_PERFORMANCE_VALUE),
            "%d[DoCacheModeNotAlignCheck] no need simpiling for topn cache, becase current is not high_performance",
            1);
        CHECK_WARNING(!(compile_params.params_d_size < SUPPORT_PARAM_SIZE),
            "[DoCacheModeNotAlignCheck] params not support uint8/int8, but type size is :%ld",
            compile_params.params_d_size);
        CHECK_WARNING(!(axis != 0), "[DoCacheModeNotAlignCheck] no need simpiling for topn cache, but axis is %ld",
            axis);
        CHECK_WARNING(!(one_param_row_size % GATHER_BLOCK_SIZE == 0),
            "[DoCacheModeNotAlignCheck] no need cache mode, but params_row is %ld",
            params.params_row);
        int64_t six_part_ub_size = (compile_params.ub_size - RESERVED_UB_SIZE_2K) / CACHE_MODE_UB_SLICE;
        six_part_ub_size = six_part_ub_size / GATHER_BLOCK_SIZE * GATHER_BLOCK_SIZE;
        int64_t align_param_row = (one_param_row_size + GATHER_BLOCK_SIZE - 1) / GATHER_BLOCK_SIZE * GATHER_BLOCK_SIZE;
        CHECK_WARNING(!(align_param_row * TRANS_POSE_LINE_SIZE > six_part_ub_size),
            "[DoCacheModeNotAlignCheck] no need cache mode, but align_param_row is %ld, params_row is %ld",
            align_param_row, params.params_row);
        CHECK_WARNING(!(compile_params.core_num == 0),
            "[DoCacheModeNotAlignCheck] no need simpiling for topn cache, but need_core_num is %ld",
            compile_params.core_num);

        return true;
    }

    bool DoCacheModeTilingNotAlian(const std::string &op_type, int64_t axis, GatherV2TilingParams &params,
        const GatherCompileParams &compile_params)
    {
        int64_t one_param_row_size = params.params_row * compile_params.params_d_size;
        if (!DoCacheModeNotAlignCheck(op_type, axis, one_param_row_size, params, compile_params)) {
            return false;
        }
        params.need_core_num = compile_params.core_num;
        params.indices_num_each_core = (params.indices_num + params.need_core_num - 1) / params.need_core_num;
        params.indices_num_remaining = params.indices_num / params.need_core_num;

        if (params.indices_num_remaining * one_param_row_size < GATHER_BLOCK_SIZE) {
            HCCL_DEBUG("[DoCacheModeTilingNotAlian] no need simpiling for topn cache, but indices_num_each_core is "
                       "%ld, params_d_size is %ld, need_core_num is %ld", op_type.c_str(),
                       params.indices_num_remaining, compile_params.params_d_size, params.need_core_num);
            return false;
        }
        params.tail_process_core = params.indices_num % params.need_core_num;
        if (params.tail_process_core == 0) {
            params.tail_process_core = params.need_core_num;
        }
        params.tiling_mode = TILING_MODE_16;

        HCCL_DEBUG("[DoCacheModeTilingNotAlian] For the core which blockId < %ld, %ld indices will be process",
                   op_type.c_str(),
                   params.tail_process_core, params.indices_num_each_core);
        HCCL_DEBUG("[DoCacheModeTilingNotAlian] For the core which blockId >= %ld, %ld indices will be process",
                   op_type.c_str(),
                   params.tail_process_core, params.indices_num_remaining);

        return true;
    }

    bool DoCpuPreprocessCheck(const std::string &op_type, int64_t axis, int64_t part_ub_size,
        GatherV2TilingParams &params, const GatherCompileParams &compile_params)
    {
        int64_t one_param_row_size = params.params_row * compile_params.params_d_size;

        CHECK_WARNING(!(part_ub_size == 0),
            "[DoCpuPreprocessCheck] no need simpiling for topn cache, but part_ub_size is %ld", part_ub_size);
        CHECK_WARNING(!(compile_params.is_preprocessed != true),
            "[DoCpuPreprocessCheck] no need simpiling for topn cache, but is_preprocessed is %u",
            compile_params.is_preprocessed);
        CHECK_WARNING(!((compile_params.params_d_size < SUPPORT_PARAM_SIZE) && (one_param_row_size %
            GATHER_BLOCK_SIZE != 0)), "[DoCpuPreprocessCheck] params not support uint8/int8, but type size is :%ld",
            one_param_row_size);
        CHECK_WARNING(!(axis != 0), "[DoCpuPreprocessCheck] no need simpiling for topn cache, but axis is %ld", axis);
        CHECK_WARNING(!(compile_params.core_num == 0),
            "[DoCpuPreprocessCheck] no need simpiling for topn cache, but need_core_num is %ld",
            compile_params.core_num);

        int64_t one_part_ub_size = (compile_params.ub_size - RESERVED_UB_SIZE_2K) / part_ub_size;
        one_part_ub_size = one_part_ub_size / GATHER_BLOCK_SIZE * GATHER_BLOCK_SIZE;
        int64_t align_param_row = (one_param_row_size + GATHER_BLOCK_SIZE - 1) / GATHER_BLOCK_SIZE * GATHER_BLOCK_SIZE;
        if (one_param_row_size % GATHER_BLOCK_SIZE != 0) {
            CHECK_WARNING(!(align_param_row * TRANS_POSE_LINE_SIZE > one_part_ub_size),
                "[DoCacheModeTilingwithCpuPreprocess]no need cache mode,but align_param_row is %ld,params_row is %ld",
                align_param_row, params.params_row);
        } else {
            CHECK_WARNING(!(align_param_row > one_part_ub_size),
                "[DoCacheModeTilingwithCpuPreprocess]no need cache mode,but align_param_row is %ld,params_row is %ld",
                align_param_row, params.params_row);
        }

        return true;
    }

    bool DoCacheModeTilingwithCpuPreprocess(const std::string &op_type, int64_t axis, GatherV2TilingParams &params,
        const GatherCompileParams &compile_params)
    {
        int64_t one_param_row_size = params.params_row * compile_params.params_d_size;

        if (one_param_row_size % GATHER_BLOCK_SIZE != 0) {
            if (!DoCpuPreprocessCheck(op_type, axis, FOUR_PART_UB_SIZE, params, compile_params)) {
                return false;
            }
        } else {
            if (!DoCpuPreprocessCheck(op_type, axis, THREE_PART_UB_SIZE, params, compile_params)) {
                return false;
            }
        }

        params.need_core_num = compile_params.core_num;
        params.indices_num_each_core = (params.indices_num + params.need_core_num - 1) / params.need_core_num;
        params.indices_num_remaining = params.indices_num / params.need_core_num;

        if (params.indices_num_remaining * one_param_row_size < GATHER_BLOCK_SIZE) {
            HCCL_DEBUG("op[%s] [DoCacheModeTilingwithCpuPreprocess] no need simpiling for topn cache,"
                       " but indices_num_remaining is %ld, params_d_size is %ld, need_core_num is %ld",
                       op_type.c_str(), params.indices_num_remaining, compile_params.params_d_size,
                       params.need_core_num);
            return false;
        }

        params.tail_process_core = params.indices_num % params.need_core_num;
        if (params.tail_process_core == 0) {
            params.tail_process_core = params.need_core_num;
        }

        if (one_param_row_size % GATHER_BLOCK_SIZE != 0) {
            params.tiling_mode = TILING_MODE_17;
        } else {
            params.tiling_mode = TILING_MODE_18;
        }

        HCCL_DEBUG("[DoCacheModeTilingwithCpuPreprocess] For the core which blockId < %ld, %ld indices will be process",
                   op_type.c_str(), params.tail_process_core, params.indices_num_each_core);
        HCCL_DEBUG("[DoCacheModeTilingwithCpuPreprocess]For the core which blockId >= %ld, %ld indices will be process",
                   op_type.c_str(), params.tail_process_core, params.indices_num_remaining);

        return true;
    }

    // compute tiling params for tiling_mode 8&9
    bool BlockLessForParamsTiling(GatherV2TilingParams &run_params, int64_t indices_num_per_loop, int64_t res_ub_size,
        int64_t params_d_size, int64_t block_num, const std::string &op_type)
    {
        if (indices_num_per_loop == 0 || block_num == 0) {
            HCCL_ERROR("op[%s],indices_num_per_loop or block_num = 0 is not support", op_type.c_str());
            return false;
        }
        run_params.indices_loop_num = run_params.indices_num_each_core / indices_num_per_loop;
        run_params.indices_row_num_once = indices_num_per_loop;
        if (run_params.indices_num_each_core % run_params.indices_row_num_once != 0) {
            run_params.indices_row_num_last = run_params.indices_num_each_core % run_params.indices_row_num_once;
        }

        run_params.row_num_once_ub = res_ub_size / (run_params.params_row * params_d_size);
        if (int(run_params.row_num_once_ub % block_num) != 0) {
            run_params.row_num_once_ub = int(run_params.row_num_once_ub / block_num) * block_num;
        }

        if (run_params.row_num_once_ub == 0) {
            HCCL_ERROR("op[%s], Devide by row_num_once_ub[%ld] exception.", op_type.c_str(),
                       run_params.row_num_once_ub);
            return false;
        }

        run_params.inner_loop_num = run_params.indices_row_num_once / run_params.row_num_once_ub;
        if (run_params.indices_row_num_once % run_params.row_num_once_ub != 0) {
            run_params.row_num_once_tail_ub = run_params.indices_row_num_once % run_params.row_num_once_ub;
        }
        if (run_params.inner_loop_num > 0 && run_params.row_num_once_tail_ub > 0 &&
            run_params.row_num_once_tail_ub * run_params.params_row < block_num) {
            run_params.inner_loop_num = run_params.inner_loop_num - 1;
            run_params.row_num_once_tail_ub = run_params.row_num_once_tail_ub + run_params.row_num_once_ub;
        }

        run_params.row_num_last_ub = res_ub_size / (run_params.params_row * params_d_size);
        if (int(run_params.row_num_last_ub % block_num) != 0) {
            run_params.row_num_last_ub = int(run_params.row_num_last_ub / block_num) * block_num;
        }

        if (run_params.row_num_last_ub == 0) {
            HCCL_ERROR("op[%s], Devide by row_num_last_ub[%ld] exception.", op_type.c_str(),
                       run_params.row_num_last_ub);
            return false;
        }

        run_params.inner_loop_num_last = run_params.indices_row_num_last / run_params.row_num_last_ub;
        if (run_params.indices_row_num_last % run_params.row_num_last_ub != 0) {
            run_params.row_num_last_tail_ub = run_params.indices_row_num_last % run_params.row_num_last_ub;
        }
        if (run_params.inner_loop_num_last > 0 && run_params.row_num_last_tail_ub > 0 &&
            run_params.row_num_last_tail_ub * run_params.params_row < block_num) {
            run_params.inner_loop_num_last = run_params.inner_loop_num_last - 1;
            run_params.row_num_last_tail_ub = run_params.row_num_last_tail_ub + run_params.row_num_once_ub;
        }

        return true;
    }

    // compute tiling params for tiling_mode 10&11&12
    bool BlockAlignForParamsTiling(GatherV2TilingParams &run_params, int64_t indices_num_per_loop, int64_t res_ub_size,
        int64_t params_d_size, const std::string &op_type)
    {
        if (indices_num_per_loop == 0) {
            HCCL_ERROR("op[%s],indices_num_per_loop = 0 is not support", op_type.c_str());
            return false;
        }
        run_params.indices_loop_num = run_params.indices_num_each_core / indices_num_per_loop;
        run_params.indices_row_num_once = indices_num_per_loop;
        if (run_params.indices_num_each_core % run_params.indices_row_num_once != 0) {
            run_params.indices_row_num_last = run_params.indices_num_each_core % run_params.indices_row_num_once;
        }

        run_params.row_num_once_ub = res_ub_size / (run_params.params_row * params_d_size);

        if (run_params.row_num_once_ub == 0) {
            HCCL_ERROR("op[%s], Devide by row_num_once_ub[%ld] exception.", op_type.c_str(),
                       run_params.row_num_once_ub);
            return false;
        }

        run_params.inner_loop_num = run_params.indices_row_num_once / run_params.row_num_once_ub;
        if (run_params.indices_row_num_once % run_params.row_num_once_ub != 0) {
            run_params.row_num_once_tail_ub = run_params.indices_row_num_once % run_params.row_num_once_ub;
        }

        run_params.row_num_last_ub = res_ub_size / (run_params.params_row * params_d_size);

        if (run_params.row_num_last_ub == 0) {
            HCCL_ERROR("op[%s], Devide by row_num_last_ub[%ld] exception.", op_type.c_str(),
                       run_params.row_num_last_ub);
            return false;
        }

        run_params.inner_loop_num_last = run_params.indices_row_num_last / run_params.row_num_last_ub;
        if (run_params.indices_row_num_last % run_params.row_num_last_ub != 0) {
            run_params.row_num_last_tail_ub = run_params.indices_row_num_last % run_params.row_num_last_ub;
        }

        return true;
    }

    // compute tiling params for tiling_mode 1&4&13
    bool BlockLessForIndicesTiling(GatherV2TilingParams &run_params, int64_t indices_num_per_loop, int64_t res_ub_size,
        int64_t params_d_size, int64_t block_num, const std::string &op_type)
    {
        if (indices_num_per_loop == 0 || block_num == 0) {
            HCCL_ERROR("op[%s], indices_num_per_loop or block_num = 0 is not support", op_type.c_str());
            return false;
        }
        run_params.indices_loop_num = run_params.indices_num_each_core / indices_num_per_loop;
        run_params.indices_row_num_once = indices_num_per_loop;
        if (run_params.indices_num_each_core % run_params.indices_row_num_once != 0) {
            run_params.indices_row_num_last = run_params.indices_num_each_core % run_params.indices_row_num_once;
        }

        run_params.row_num_once_ub = res_ub_size / (run_params.params_row * params_d_size);
        if (int(run_params.row_num_once_ub % block_num) != 0) {
            run_params.row_num_once_ub = int(run_params.row_num_once_ub / block_num) * block_num;
        }

        if (run_params.row_num_once_ub == 0) {
            HCCL_ERROR("op[%s], Devide by row_num_once_ub[%ld] exception.", op_type.c_str(),
                       run_params.row_num_once_ub);
            return false;
        }

        run_params.inner_loop_num = run_params.indices_row_num_once / run_params.row_num_once_ub;
        if (run_params.indices_row_num_once % run_params.row_num_once_ub != 0) {
            run_params.row_num_once_tail_ub = run_params.indices_row_num_once % run_params.row_num_once_ub;
        }
        if (run_params.inner_loop_num > 0 && run_params.row_num_once_tail_ub > 0 &&
            run_params.row_num_once_tail_ub * run_params.params_row < block_num) {
            run_params.inner_loop_num = run_params.inner_loop_num - 1;
            run_params.row_num_once_tail_ub = run_params.row_num_once_tail_ub + run_params.row_num_once_ub;
        }

        run_params.row_num_last_ub = res_ub_size / (run_params.params_row * params_d_size);
        if (int(run_params.row_num_last_ub % block_num) != 0) {
            run_params.row_num_last_ub = int(run_params.row_num_last_ub / block_num) * block_num;
        }

        if (run_params.row_num_last_ub == 0) {
            HCCL_ERROR("op[%s], Devide by row_num_last_ub[%ld] exception.", op_type.c_str(),
                       run_params.row_num_last_ub);
            return false;
        }

        run_params.inner_loop_num_last = run_params.indices_row_num_last / run_params.row_num_last_ub;
        if (run_params.indices_row_num_last % run_params.row_num_last_ub != 0) {
            run_params.row_num_last_tail_ub = run_params.indices_row_num_last % run_params.row_num_last_ub;
        }
        if (run_params.inner_loop_num_last > 0 && run_params.row_num_last_tail_ub > 0 &&
            run_params.row_num_last_tail_ub * run_params.params_row < block_num) {
            run_params.inner_loop_num_last = run_params.inner_loop_num_last - 1;
            run_params.row_num_last_tail_ub = run_params.row_num_last_tail_ub + run_params.row_num_once_ub;
        }

        return true;
    }

    // compute tiling params for tiling_mode 3&6&7
    bool BlockAlignForIndicesTiling(GatherV2TilingParams &run_params, int64_t indices_num_per_loop, int64_t res_ub_size,
        int64_t params_d_size, const std::string &op_type)
    {
        if (indices_num_per_loop == 0) {
            HCCL_ERROR("op[%s], indices_num_per_loop = 0 is not support", op_type.c_str());
            return false;
        }
        run_params.indices_loop_num = run_params.indices_num_each_core / indices_num_per_loop;
        run_params.indices_row_num_once = indices_num_per_loop;
        if (run_params.indices_num_each_core % run_params.indices_row_num_once != 0) {
            run_params.indices_row_num_last = run_params.indices_num_each_core % run_params.indices_row_num_once;
        }

        run_params.row_num_once_ub = res_ub_size / (run_params.params_row * params_d_size);
        if (run_params.row_num_once_ub == 0) {
            HCCL_ERROR("op[%s], Devide by row_num_once_ub[%ld] exception.", op_type.c_str(),
                       run_params.row_num_once_ub);
            return false;
        }

        run_params.inner_loop_num = run_params.indices_row_num_once / run_params.row_num_once_ub;
        if (run_params.indices_row_num_once % run_params.row_num_once_ub != 0) {
            run_params.row_num_once_tail_ub = run_params.indices_row_num_once % run_params.row_num_once_ub;
        }

        run_params.row_num_last_ub = res_ub_size / (run_params.params_row * params_d_size);

        if (run_params.row_num_last_ub == 0) {
            HCCL_ERROR("op[%s], Devide by row_num_last_ub[%ld] exception.", op_type.c_str(),
                       run_params.row_num_last_ub);
            return false;
        }

        run_params.inner_loop_num_last = run_params.indices_row_num_last / run_params.row_num_last_ub;
        if (run_params.indices_row_num_last % run_params.row_num_last_ub != 0) {
            run_params.row_num_last_tail_ub = run_params.indices_row_num_last % run_params.row_num_last_ub;
        }

        return true;
    }

    bool CalcWithBatchDims(GatherV2TilingParams &run_params, int64_t indices_num_per_loop, int64_t res_ub_size,
        int64_t params_d_size)
    {
        if (indices_num_per_loop == 0 || params_d_size == 0) {
            HCCL_ERROR("gather_v2, indices_num_per_loop or params_d_size= 0 is not support");
            return false;
        }
        run_params.indices_loop_num = run_params.indices_row / indices_num_per_loop;
        run_params.indices_row_num_once = indices_num_per_loop;
        int64_t block_num = GATHER_BLOCK_SIZE / params_d_size;
        if (run_params.params_row * params_d_size >= GATHER_BLOCK_SIZE) {
            block_num = 1;
        }
        if (run_params.indices_row % run_params.indices_row_num_once != 0) {
            run_params.indices_row_num_last = run_params.indices_num_each_core % run_params.indices_row_num_once;
        }
        if (run_params.indices_loop_num > 0 &&
            run_params.indices_row_num_last * run_params.indices_row * run_params.params_row < block_num) {
            run_params.indices_loop_num -= 1;
            run_params.indices_row_num_last += run_params.indices_row_num_once;
        }

        run_params.row_num_once_ub = res_ub_size / (run_params.params_row * params_d_size);
        if (int(run_params.row_num_once_ub % block_num) != 0) {
            run_params.row_num_once_ub = int(run_params.row_num_once_ub / block_num) * block_num;
        }
        CHECK(!(run_params.row_num_once_ub == 0), "Gather Tiling:", "Devide by row_num_once_ub[%ld] exception.",
              run_params.row_num_once_ub);
        run_params.inner_loop_num = run_params.indices_row_num_once / run_params.row_num_once_ub;
        if (run_params.indices_row_num_once % run_params.row_num_once_ub != 0) {
            run_params.row_num_once_tail_ub = run_params.indices_row_num_once % run_params.row_num_once_ub;
        }
        if (run_params.inner_loop_num > 0 && run_params.row_num_once_tail_ub > 0 &&
            run_params.row_num_once_tail_ub * run_params.params_row < block_num) {
            run_params.inner_loop_num = run_params.inner_loop_num - 1;
            run_params.row_num_once_tail_ub = run_params.row_num_once_tail_ub + run_params.row_num_once_ub;
        }

        run_params.row_num_last_ub = run_params.row_num_once_ub;
        run_params.inner_loop_num_last = run_params.indices_row_num_last / run_params.row_num_once_ub;
        if (run_params.indices_row_num_last % run_params.row_num_once_ub != 0) {
            run_params.row_num_last_tail_ub = run_params.indices_row_num_last % run_params.row_num_once_ub;
        }
        if (run_params.inner_loop_num_last > 0 && run_params.row_num_last_tail_ub > 0 &&
            run_params.row_num_last_tail_ub * run_params.params_row < block_num) {
            run_params.inner_loop_num_last = run_params.inner_loop_num_last - 1;
            run_params.row_num_last_tail_ub = run_params.row_num_last_tail_ub + run_params.row_num_once_ub;
        }

        return true;
    }

    bool CalcCacheIndices(GatherV2TilingParams &run_params, int64_t indices_num_per_loop, int64_t res_ub_size,
        int64_t params_d_size, int64_t tiling_mode)
    {
        if (params_d_size == 0) {
            HCCL_ERROR("gather_v2, params_d_size= 0 is not support");
            return false;
        }
        run_params.indices_row_num_once = indices_num_per_loop;
        run_params.row_num_once_ub = res_ub_size / (run_params.params_row * params_d_size);
        int64_t block_num = GATHER_BLOCK_SIZE / params_d_size;
        int64_t align_unit;
        if (tiling_mode == TILING_MODE_38 || tiling_mode == TILING_MODE_39) {
            align_unit = run_params.indices_row * block_num;
        } else if (tiling_mode == TILING_MODE_40 || tiling_mode == TILING_MODE_41) {
            align_unit = run_params.params_pre * run_params.indices_row * block_num;
        } else if (run_params.params_row * params_d_size >= GATHER_BLOCK_SIZE) {
            align_unit = 1;
        } else {
            align_unit = block_num;
        }

        if (int(run_params.row_num_once_ub % align_unit) != 0) {
            run_params.row_num_once_ub = int(run_params.row_num_once_ub / align_unit) * align_unit;
        }
        CHECK(!(run_params.row_num_once_ub == 0), "Gather Tiling:, Devide by row_num_once_ub[%ld] exception.",
              run_params.row_num_once_ub);
        run_params.inner_loop_num = run_params.indices_row_num_once / run_params.row_num_once_ub;
        if (run_params.indices_row_num_once % run_params.row_num_once_ub != 0) {
            run_params.row_num_once_tail_ub = run_params.indices_row_num_once % run_params.row_num_once_ub;
        }
        if (run_params.inner_loop_num > 0 && run_params.row_num_once_tail_ub > 0 &&
            run_params.row_num_once_tail_ub * run_params.params_row < block_num) {
            run_params.inner_loop_num = run_params.inner_loop_num - 1;
            run_params.row_num_once_tail_ub = run_params.row_num_once_tail_ub + run_params.row_num_once_ub;
        }
        run_params.tiling_mode = tiling_mode;

        return true;
    }

    void CalNeedCore(GatherV2TilingParams &run_params, const GatherCompileParams &compile_params)
    {
        while (run_params.need_core_num > 1) {
            run_params.need_core_num = run_params.need_core_num / 2;
            run_params.indices_num_each_core = run_params.indices_num / run_params.need_core_num;
            run_params.indices_num_remaining = run_params.indices_num % run_params.need_core_num;
            if (run_params.indices_num_each_core * run_params.params_row * compile_params.params_d_size >
                GATHER_BLOCK_SIZE) {
                break;
            }
        }
    }

    void CalNeedCoreWithBatchDims(GatherV2TilingParams &run_params, const GatherCompileParams &compile_params)
    {
        while (run_params.need_core_num > 1) {
            run_params.need_core_num = run_params.need_core_num / 2;
            run_params.params_batch_each_core = run_params.params_batch / run_params.need_core_num;
            run_params.params_batch_remaining = run_params.params_batch % run_params.need_core_num;
            run_params.indices_num_each_core = run_params.params_batch_each_core * run_params.indices_row;
            run_params.indices_num_remaining = run_params.params_batch_remaining * run_params.indices_row;
            if (run_params.indices_num_each_core * run_params.params_pre * run_params.params_row *
                compile_params.params_d_size >
                GATHER_BLOCK_SIZE) {
                break;
            }
        }
    }

    bool TilingWithoutBatchDims(const std::string &op_type, GatherV2TilingParams &run_params,
        GatherCompileParams &compile_params, const GatherShapeInfo &shape_info, int64_t axis)
    {
        int64_t available_ub_size = compile_params.ub_size - 2 * 1024;  // reserved 2K
        int64_t half_ub_size = available_ub_size / 2;
        int64_t block_num = GATHER_BLOCK_SIZE / compile_params.params_d_size;

        // params shape convert to 3D:[params_pre, params_axis, params_row]
        // indices shape convert to 1D:[indices_num]
        // output tensor, y shape convert to:[params_pre, indices_num, params_row]
        if (axis == 0) {
            run_params.params_pre = 1;
        } else {
            for (int i = 0; i < axis; i++) {
                run_params.params_pre *= shape_info.params_shape[i];
            }
        }
        run_params.params_axis = shape_info.params_shape[axis];
        int64_t paramsDims = shape_info.params_shape.size();
        if (axis + 1 < paramsDims) {
            for (int i = axis + 1; i < paramsDims; i++) {
                run_params.params_row *= shape_info.params_shape[i];
            }
        } else {
            run_params.params_row = 1;
        }

        if (run_params.params_row * compile_params.params_d_size < GATHER_BLOCK_SIZE) {
            compile_params.impl_mode = IMPL_MODE_DEFAULT_VALUE;
            HCCL_WARNING("op[%s], [GatherV2TIKTiling] impl_mode reset to DEFAULT_VALUE for small params row",
                op_type.c_str());
        }
        run_params.params_total =
                std::accumulate(shape_info.params_shape.begin(), shape_info.params_shape.end(), 1,
                                std::multiplies<int64_t>());

        int64_t params_total_ceil = (run_params.params_total + block_num - 1) / block_num * block_num;
        int64_t params_row_ceil = (run_params.params_row + block_num - 1) / block_num * block_num;
        int64_t indices_dims = shape_info.indices_shape.size();
        for (int i = 0; i < indices_dims; i++) {
            run_params.indices_num *= shape_info.indices_shape[i];
        }

        int64_t res_ub_size = half_ub_size;  // store params row data
        int64_t half_ub_indices_elem = half_ub_size / compile_params.indices_d_size;
        int64_t indices_num_per_loop = half_ub_indices_elem;
        int64_t half_remain_ub_size = (available_ub_size - PARAMS_CACHED_UB) / HALF_UB;
        int64_t half_remain_params_elem = half_remain_ub_size / compile_params.params_d_size;
        int64_t half_ub_params_elem = half_ub_size / compile_params.params_d_size;

        // the data of the formula gained from actual tests
        // set a gate value for tiling_mode_7 to optimized some data_move processes
        float mode_7_gate_value = ACTUAL_NUM - GATE_VALUE * run_params.params_total / DATA_VALUE;

        if (DoCacheModeTilingwithCpuPreprocess(op_type, axis, run_params, compile_params)) {
            HCCL_WARNING("op[%s], [GatherV2TIKTiling] end of tiling cache is DoCacheMode with CpuPreprocess",
                op_type.c_str());
            return true;
        }

        if (DoCacheModeTiling(op_type, axis, run_params, compile_params)) {
            run_params.tiling_mode = TILING_MODE_15;
            HCCL_WARNING("op[%s], [GatherV2TIKTiling] end of tiling cache is high_performance", op_type.c_str());
            return true;
        }

        if (DoCacheModeTilingNotAlian(op_type, axis, run_params, compile_params)) {
            HCCL_WARNING("op[%s], [GatherV2TIKTiling] end of tiling cache is high_performance", op_type.c_str());
            return true;
        }

        if (DoImplModeTiling(op_type, run_params, compile_params)) {
            run_params.tiling_mode = TILING_MODE_14;
            HCCL_WARNING("op[%s], [GatherV2TIKTiling] end of tiling for impl_mode is high_performance",
                op_type.c_str());
            PrintGatherV2Params(run_params, op_type);
            return true;
        } else if (run_params.params_pre >= compile_params.core_num && params_row_ceil <= half_ub_params_elem &&
                   (run_params.params_row * compile_params.params_d_size < GATHER_BLOCK_SIZE ||
                    run_params.params_row * compile_params.params_d_size % GATHER_BLOCK_SIZE == 0)) {
            // block tiling: params_pre tiling
            run_params.need_core_num = compile_params.core_num;
            run_params.tail_process_core = 0;
            run_params.params_pre_each_core = run_params.params_pre / run_params.need_core_num;
            run_params.params_pre_remaining = run_params.params_pre % run_params.need_core_num;
            run_params.indices_num_each_core = run_params.indices_num;

            if (run_params.indices_num_each_core * run_params.params_row * compile_params.params_d_size <=
                GATHER_BLOCK_SIZE) {
                run_params.need_core_num = 1;
                run_params.tail_process_core = 0;
                run_params.params_pre_each_core = run_params.params_pre;
                run_params.params_pre_remaining = 0;
            }

            if (run_params.params_row * compile_params.params_d_size < GATHER_BLOCK_SIZE) {
                if (params_total_ceil <= PARAMS_CACHED_UB / compile_params.params_d_size) {
                    run_params.tiling_mode = TILING_MODE_8;
                } else {
                    run_params.tiling_mode = TILING_MODE_9;
                }

                if (run_params.tiling_mode == TILING_MODE_8) {
                    indices_num_per_loop = half_remain_ub_size / compile_params.indices_d_size;
                    res_ub_size = half_remain_ub_size;
                }

                if (!BlockLessForParamsTiling(run_params, indices_num_per_loop, res_ub_size,
                                              compile_params.params_d_size,
                                              block_num, op_type)) {
                    PrintGatherV2Params(run_params, op_type);
                    return false;
                }
            } else {
                if (params_total_ceil <= PARAMS_CACHED_UB / compile_params.params_d_size &&
                    params_row_ceil <= half_remain_params_elem) {
                    run_params.tiling_mode = TILING_MODE_10;
                } else if (params_total_ceil <= compile_params.l1_size / compile_params.params_d_size) {
                    run_params.tiling_mode = TILING_MODE_11;
                } else {
                    run_params.tiling_mode = TILING_MODE_12;
                }

                if (run_params.tiling_mode == TILING_MODE_10) {
                    indices_num_per_loop = half_remain_ub_size / compile_params.indices_d_size;
                    res_ub_size = half_remain_ub_size;
                }

                if (!BlockAlignForParamsTiling(run_params, indices_num_per_loop, res_ub_size,
                                               compile_params.params_d_size, op_type)) {
                    PrintGatherV2Params(run_params, op_type);
                    return false;
                }
            }
        } else {
            // block tiling: indices tiling
            run_params.need_core_num = compile_params.core_num;
            run_params.tail_process_core = 0;
            run_params.indices_num_each_core = run_params.indices_num / run_params.need_core_num;
            run_params.indices_num_remaining = run_params.indices_num % run_params.need_core_num;
            if (run_params.indices_num <= run_params.need_core_num) {
                run_params.need_core_num = run_params.indices_num;
                run_params.tail_process_core = 0;
                run_params.indices_num_each_core = 1;
                run_params.indices_num_remaining = 0;
            }

            // one params row size is smaller than 32B
            if (run_params.params_row * compile_params.params_d_size < GATHER_BLOCK_SIZE) {
                if (params_total_ceil <= PARAMS_CACHED_UB / compile_params.params_d_size) {
                    run_params.tiling_mode = TILING_MODE_4;
                } else if (params_total_ceil <= compile_params.l1_size / compile_params.params_d_size) {
                    run_params.tiling_mode = TILING_MODE_13;
                } else {
                    run_params.tiling_mode = TILING_MODE_1;
                }

                if ((run_params.params_row < GATHER_BLOCK_SIZE) &&
                    run_params.indices_num_each_core * run_params.params_row * compile_params.params_d_size <=
                    GATHER_BLOCK_SIZE) {
                    CalNeedCore(run_params, compile_params);
                }

                if (run_params.tiling_mode == TILING_MODE_4) {
                    indices_num_per_loop = half_remain_ub_size / compile_params.indices_d_size;
                    res_ub_size = half_remain_ub_size;
                }

                if (!BlockLessForIndicesTiling(run_params, indices_num_per_loop, res_ub_size,
                                               compile_params.params_d_size,
                                               block_num, op_type)) {
                    PrintGatherV2Params(run_params, op_type);
                    return false;
                }
            } else {  // one params row size is greater than or equal to 32B
                if (params_row_ceil <= half_ub_params_elem) {
                    if (run_params.params_row * compile_params.params_d_size % GATHER_BLOCK_SIZE !=
                        0) {  // not 32B aligned
                        run_params.tiling_mode = TILING_MODE_2;

                        run_params.indices_loop_num = run_params.indices_num_each_core / half_ub_indices_elem;
                        run_params.indices_row_num_once = half_ub_indices_elem;
                        if (run_params.indices_num_each_core % run_params.indices_row_num_once != 0) {
                            run_params.indices_row_num_last =
                                    run_params.indices_num_each_core % run_params.indices_row_num_once;
                        }
                    } else {  // 32B aligned
                        if (params_total_ceil <= PARAMS_CACHED_UB / compile_params.params_d_size &&
                            params_row_ceil <= half_remain_params_elem) {
                            run_params.tiling_mode = TILING_MODE_6;
                        } else if (params_total_ceil <= compile_params.l1_size / compile_params.params_d_size &&
                                   run_params.indices_num > mode_7_gate_value) {
                            run_params.tiling_mode = TILING_MODE_7;
                        } else {
                            run_params.tiling_mode = TILING_MODE_3;
                        }

                        if (run_params.tiling_mode == TILING_MODE_6) {
                            indices_num_per_loop = half_remain_ub_size / compile_params.indices_d_size;
                            res_ub_size = half_remain_ub_size;
                        }

                        if (!BlockAlignForIndicesTiling(run_params, indices_num_per_loop, res_ub_size,
                                                        compile_params.params_d_size, op_type)) {
                            PrintGatherV2Params(run_params, op_type);
                            return false;
                        }
                    }
                } else {
                    run_params.tiling_mode = TILING_MODE_5;  // one params row need tiling

                    run_params.indices_loop_num = run_params.indices_num_each_core / half_ub_indices_elem;
                    run_params.indices_row_num_once = indices_num_per_loop;
                    if (run_params.indices_num_each_core % run_params.indices_row_num_once != 0) {
                        run_params.indices_row_num_last =
                                run_params.indices_num_each_core % run_params.indices_row_num_once;
                    }

                    run_params.one_row_loop = run_params.params_row / half_ub_params_elem;
                    run_params.one_row_tail = run_params.params_row % half_ub_params_elem;
                    if (run_params.one_row_loop > 0 && run_params.one_row_tail > 0 &&
                        run_params.one_row_tail < block_num) {
                        run_params.one_row_loop = run_params.one_row_loop - 1;
                        run_params.one_row_tail = half_ub_params_elem + run_params.one_row_tail;
                    }
                }
            }
        }
        PrintGatherV2Params(run_params, op_type);
        return true;
    }

    void ParasPreProcess(GatherV2TilingParams &run_params, const GatherCompileParams &compile_params,
        const GatherShapeInfo &shape_info, int64_t axis)
    {
        int64_t batch_dims = compile_params.batch_dims;
        int64_t indices_dims = shape_info.indices_shape.size();

        // params shape convert to 4D:[params_batch, params_pre, params_axis, params_row]
        // indices shape convert to 1D:[indicesBatch, indices_row]
        // output tensor, y shape convert to:[params_batch, params_pre, indices_row, params_row]
        for (int i = 0; i < batch_dims; i++) {
            run_params.indicesBatch *= shape_info.indices_shape[i];
        }
        run_params.params_batch = run_params.indicesBatch;
        for (int i = batch_dims; i < indices_dims; i++) {
            run_params.indices_row *= shape_info.indices_shape[i];
        }

        if (axis == batch_dims) {
            run_params.params_pre = 1;
        } else {
            for (int i = batch_dims; i < axis; i++) {
                run_params.params_pre *= shape_info.params_shape[i];
            }
        }
        run_params.params_axis = shape_info.params_shape[axis];
        int64_t paramsDims = shape_info.params_shape.size();
        if (axis + 1 < paramsDims) {
            for (int i = axis + 1; i < paramsDims; i++) {
                run_params.params_row *= shape_info.params_shape[i];
            }
        } else {
            run_params.params_row = 1;
        }

        for (int i = 0; i < indices_dims; i++) {
            run_params.indices_num *= shape_info.indices_shape[i];
        }
    }

    bool SmallRowProcess(GatherV2TilingParams &run_params, const GatherCompileParams &compile_params,
        int64_t mode_with_cache, int64_t mode_without_cache)
    {
        if (mode_with_cache == TILING_MODE_38 || mode_without_cache == TILING_MODE_39) {
            run_params.params_batch_each_core = run_params.params_pre / run_params.need_core_num;
            run_params.params_batch_remaining = run_params.params_pre % run_params.need_core_num;
        }
        run_params.tail_process_core = run_params.need_core_num - 1;
        run_params.indices_num_each_core = run_params.params_batch_each_core * run_params.indices_row;
        run_params.indices_num_remaining = 0;
        int64_t block_num = GATHER_BLOCK_SIZE / compile_params.params_d_size;
        int64_t indices_num_per_loop = run_params.indices_num_each_core;
        int64_t params_total_ceil = (run_params.params_total + block_num - 1) / block_num * block_num;
        int64_t params_row_ceil = (run_params.params_row + block_num - 1) / block_num * block_num;
        int64_t half_remain_params_elem = run_params.half_remain_ub_size / compile_params.params_d_size;
        if (params_total_ceil <= PARAMS_CACHED_UB / compile_params.params_d_size &&
            params_row_ceil <= half_remain_params_elem) {
            if (!CalcCacheIndices(run_params, indices_num_per_loop, run_params.half_remain_ub_size,
                                  compile_params.params_d_size, mode_with_cache)) {
                return false;
            }
        } else {
            if (!CalcCacheIndices(run_params, indices_num_per_loop, run_params.half_ub_size,
                                  compile_params.params_d_size,
                                  mode_without_cache)) {
                return false;
            }
        }
        return true;
    }

    bool IndicesCachedProcess(GatherV2TilingParams &run_params, const GatherCompileParams &compile_params,
        int64_t aval_ub_size, int64_t mode_cache_all, int64_t mode_cache_row, int64_t mode_without_cache)
    {
        int64_t indices_num_per_loop = 1;
        if (run_params.params_batch_each_core * run_params.indices_row * compile_params.indices_d_size <=
            aval_ub_size) {
            indices_num_per_loop = run_params.indices_row;
            if (!CalcCacheIndices(run_params, indices_num_per_loop, aval_ub_size, compile_params.params_d_size,
                                  mode_cache_all)) {
                return false;
            }
        } else if (run_params.indices_row * compile_params.indices_d_size <= aval_ub_size) {
            indices_num_per_loop = run_params.indices_row;
            if (!CalcCacheIndices(run_params, indices_num_per_loop, aval_ub_size, compile_params.params_d_size,
                                  mode_cache_row)) {
                return false;
            }
        } else {
            indices_num_per_loop = aval_ub_size / compile_params.indices_d_size;
            run_params.tiling_mode = mode_without_cache;
            if (!CalcWithBatchDims(run_params, indices_num_per_loop, aval_ub_size, compile_params.params_d_size)) {
                return false;
            }
        }
        return true;
    }

    bool LargeRowProcess(GatherV2TilingParams &run_params, const GatherCompileParams &compile_params,
        int64_t half_ub_params_elem)
    {
        if (half_ub_params_elem == 0) {
            HCCL_ERROR("gather_v2, half_ub_params_elem = 0 is not support");
            return false;
        }
        run_params.one_row_loop = run_params.params_row / half_ub_params_elem;
        run_params.one_row_tail = run_params.params_row % half_ub_params_elem;
        int64_t block_num = GATHER_BLOCK_SIZE / compile_params.params_d_size;
        if (run_params.one_row_loop > 0 && run_params.one_row_tail > 0 && run_params.one_row_tail < block_num) {
            run_params.one_row_loop = run_params.one_row_loop - 1;
            run_params.one_row_tail = half_ub_params_elem + run_params.one_row_tail;
        }

        if (run_params.params_batch_each_core * run_params.indices_row * compile_params.indices_d_size <=
            run_params.half_ub_size) {
            run_params.indices_row_num_once = run_params.indices_row;
            run_params.tiling_mode = TILING_MODE_35;
        } else if (run_params.indices_row * compile_params.indices_d_size <= run_params.half_ub_size) {
            run_params.indices_row_num_once = run_params.indices_row;
            run_params.tiling_mode = TILING_MODE_36;
        } else {
            int64_t indices_num_per_loop = run_params.half_ub_size / compile_params.indices_d_size;
            run_params.indices_loop_num = run_params.indices_row / indices_num_per_loop;
            run_params.indices_row_num_once = indices_num_per_loop;
            if (run_params.indices_row % run_params.indices_row_num_once != 0) {
                run_params.indices_row_num_last = run_params.indices_num_each_core % run_params.indices_row_num_once;
            }
            run_params.tiling_mode = TILING_MODE_37;
        }
        return true;
    }

    bool TilingWithBatchDims(GatherV2TilingParams &run_params, const GatherCompileParams &compile_params,
        const GatherShapeInfo &shape_info, int64_t axis)
    {
        int64_t available_ub_size = compile_params.ub_size - 2 * 1024;  // reserved 2K
        run_params.half_ub_size = available_ub_size / 2;
        int64_t block_num = GATHER_BLOCK_SIZE / compile_params.params_d_size;
        ParasPreProcess(run_params, compile_params, shape_info, axis);

        run_params.half_remain_ub_size = (available_ub_size - PARAMS_CACHED_UB) / HALF_UB;
        int64_t half_remain_params_elem = run_params.half_remain_ub_size / compile_params.params_d_size;
        int64_t half_ub_params_elem = run_params.half_ub_size / compile_params.params_d_size;

        run_params.need_core_num =
                (run_params.indicesBatch < compile_params.core_num) ? run_params.indicesBatch : compile_params.core_num;
        run_params.tail_process_core = 0;
        run_params.params_batch_each_core = run_params.params_batch / run_params.need_core_num;
        run_params.params_batch_remaining = run_params.params_batch % run_params.need_core_num;
        run_params.indices_num_each_core = run_params.params_batch_each_core * run_params.indices_row;
        run_params.indices_num_remaining = run_params.params_batch_remaining * run_params.indices_row;

        if (run_params.indices_num_each_core * run_params.params_row * compile_params.params_d_size <=
            GATHER_BLOCK_SIZE) {
            run_params.need_core_num = 1;
            run_params.tail_process_core = 0;
            run_params.params_batch_each_core = run_params.params_batch;
            run_params.params_batch_remaining = 0;
            run_params.indices_num_each_core = run_params.params_batch_each_core * run_params.indices_row;
            run_params.indices_num_remaining = run_params.params_batch_remaining * run_params.indices_row;
        }
        run_params.params_total =
                run_params.params_batch_each_core * run_params.params_pre * run_params.params_axis *
                run_params.params_row;
        int64_t params_total_ceil = (run_params.params_total + block_num - 1) / block_num * block_num;
        int64_t params_row_ceil = (run_params.params_row + block_num - 1) / block_num * block_num;

        if (run_params.params_row * compile_params.params_d_size < GATHER_BLOCK_SIZE) {
            if (run_params.indices_row * run_params.params_row * compile_params.params_d_size <= GATHER_BLOCK_SIZE) {
                if (run_params.params_pre * run_params.indices_row * run_params.params_row *
                    compile_params.params_d_size <=
                    NUM_32 * GATHER_BLOCK_SIZE) {
                    if (run_params.indices_num_each_core * run_params.params_row * compile_params.params_d_size <=
                        GATHER_BLOCK_SIZE) {
                        CalNeedCoreWithBatchDims(run_params, compile_params);
                    }
                    run_params.params_total =
                            run_params.params_batch_each_core * run_params.params_pre * run_params.params_axis *
                            run_params.params_row;
                    if (!SmallRowProcess(run_params, compile_params, TILING_MODE_40, TILING_MODE_41)) {
                        return false;
                    }
                } else {
                    run_params.need_core_num =
                            (run_params.params_pre < compile_params.core_num) ? run_params.params_pre
                                                                              : compile_params.core_num;
                    run_params.params_total =
                            run_params.params_batch * run_params.params_pre * run_params.params_axis *
                            run_params.params_row;
                    if (!SmallRowProcess(run_params, compile_params, TILING_MODE_38, TILING_MODE_39)) {
                        return false;
                    }
                }
                return true;
            }
            if (params_total_ceil <= PARAMS_CACHED_UB / compile_params.params_d_size &&
                params_row_ceil <= half_remain_params_elem) {
                if (!IndicesCachedProcess(run_params, compile_params, run_params.half_remain_ub_size, TILING_MODE_20,
                                          TILING_MODE_21, TILING_MODE_22)) {
                    return false;
                }
            } else {
                if (!IndicesCachedProcess(run_params, compile_params, run_params.half_ub_size, TILING_MODE_23,
                                          TILING_MODE_24,
                                          TILING_MODE_25)) {
                    return false;
                }
            }
        } else {
            if (params_row_ceil <= half_ub_params_elem) {
                if (run_params.params_row * compile_params.params_d_size % GATHER_BLOCK_SIZE != 0) {
                    if (!IndicesCachedProcess(run_params, compile_params, run_params.half_ub_size, TILING_MODE_26,
                                              TILING_MODE_27,
                                              TILING_MODE_28)) {
                        return false;
                    }
                } else {
                    if (params_total_ceil <= PARAMS_CACHED_UB / compile_params.params_d_size &&
                        params_row_ceil <= half_remain_params_elem) {
                        if (!IndicesCachedProcess(run_params, compile_params, run_params.half_remain_ub_size,
                                                  TILING_MODE_29,
                                                  TILING_MODE_30, TILING_MODE_31)) {
                            return false;
                        }
                    } else {
                        if (!IndicesCachedProcess(run_params, compile_params, run_params.half_ub_size, TILING_MODE_32,
                                                  TILING_MODE_33,
                                                  TILING_MODE_34)) {
                            return false;
                        }
                    }
                }
            } else {
                if (!LargeRowProcess(run_params, compile_params, half_ub_params_elem)) {
                    return false;
                }
            }
        }
        return true;
    }

    bool GatherTIKTiling(const std::string &op_type, const TeOpParas &op_paras, const GatherCompileInfos &op_info,
        OpRunInfo &run_info)
    {
        HCCL_INFO("op[%s] op tiling begin.", op_type.c_str());
        GatherShapeInfo shape_info;
        InitGatherShapeInfo(op_type, shape_info, op_paras);

        // input axis index is 2 get const data values[0];
        int64_t axis = 0;
        GatherCompileParams compile_params;
        InitGatherCompileParams(compile_params);
        GetV2GatherCompileParams(op_type, op_info, op_paras, compile_params);
        CHECK(CheckAxisAndBatchdims(op_type, shape_info, axis, compile_params), "op[%s] [CheckAxisAndBatchdims] failed",
              op_type.c_str());

        GatherV2TilingParams run_params;
        InitGatherV2Params(run_params);

        if (compile_params.batch_dims == 0) {
            if (!TilingWithoutBatchDims(op_type, run_params, compile_params, shape_info, axis)) {
                HCCL_ERROR("op[%s] GatherV2Tiling: [TilingWithoutBatchDims] failed.", op_type.c_str());
                return false;
            }
        } else {
            if (!TilingWithBatchDims(run_params, compile_params, shape_info, axis)) {
                HCCL_ERROR("op[%s] GatherV2Tiling: [TilingWithBatchDims] failed.", op_type.c_str());
                return false;
            }
        }

        SetGatherV2Params(run_params, run_info);
        PrintGatherV2Params(run_params, op_type);
        run_info.blockDim = static_cast<uint32_t>(run_params.need_core_num);

        return true;
    }
}
